home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / perl / perl5a1.lha / perl5alpha1 / doio.c < prev    next >
C/C++ Source or Header  |  1993-07-31  |  32KB  |  1,551 lines

  1. /* $RCSfile: doio.c,v $$Revision: 4.1 $$Date: 92/08/07 17:19:42 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    doio.c,v $
  9.  * Revision 4.1  92/08/07  17:19:42  lwall
  10.  * Stage 6 Snapshot
  11.  * 
  12.  * Revision 4.0.1.6  92/06/11  21:08:16  lwall
  13.  * patch34: some systems don't declare h_errno extern in header files
  14.  * 
  15.  * Revision 4.0.1.5  92/06/08  13:00:21  lwall
  16.  * patch20: some machines don't define ENOTSOCK in errno.h
  17.  * patch20: new warnings for failed use of stat operators on filenames with \n
  18.  * patch20: wait failed when STDOUT or STDERR reopened to a pipe
  19.  * patch20: end of file latch not reset on reopen of STDIN
  20.  * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
  21.  * patch20: fixed memory leak on system() for vfork() machines
  22.  * patch20: get*by* routines now return something useful in a scalar context
  23.  * patch20: h_errno now accessible via $?
  24.  * 
  25.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  26.  * patch11: prepared for ctype implementations that don't define isascii()
  27.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  28.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  29.  * patch11: certain perl errors should set EBADF so that $! looks better
  30.  * patch11: truncate on a closed filehandle could dump
  31.  * patch11: stats of _ forgot whether prior stat was actually lstat
  32.  * patch11: -T returned true on NFS directory
  33.  * 
  34.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  35.  * patch10: read didn't work from character special files open for writing
  36.  * patch10: close-on-exec wrongly set on system file descriptors
  37.  * 
  38.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  39.  * patch4: new copyright notice
  40.  * patch4: system fd's are now treated specially
  41.  * patch4: added $^F variable to specify maximum system fd, default 2
  42.  * patch4: character special files now opened with bidirectional stdio buffers
  43.  * patch4: taintchecks could improperly modify parent in vfork()
  44.  * patch4: many, many itty-bitty portability fixes
  45.  * 
  46.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  47.  * patch1: hopefully straightened out some of the Xenix mess
  48.  * 
  49.  * Revision 4.0  91/03/20  01:07:06  lwall
  50.  * 4.0 baseline.
  51.  * 
  52.  */
  53.  
  54. #include "EXTERN.h"
  55. #include "perl.h"
  56.  
  57. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  58. #include <sys/ipc.h>
  59. #ifdef HAS_MSG
  60. #include <sys/msg.h>
  61. #endif
  62. #ifdef HAS_SEM
  63. #include <sys/sem.h>
  64. #endif
  65. #ifdef HAS_SHM
  66. #include <sys/shm.h>
  67. #endif
  68. #endif
  69.  
  70. #ifdef I_UTIME
  71. #include <utime.h>
  72. #endif
  73. #ifdef I_FCNTL
  74. #include <fcntl.h>
  75. #endif
  76. #ifdef I_SYS_FILE
  77. #include <sys/file.h>
  78. #endif
  79.  
  80. bool
  81. do_open(gv,name,len)
  82. GV *gv;
  83. register char *name;
  84. I32 len;
  85. {
  86.     FILE *fp;
  87.     register IO *io = GvIO(gv);
  88.     char *myname = savestr(name);
  89.     int result;
  90.     int fd;
  91.     int writing = 0;
  92.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  93.     FILE *saveifp = Nullfp;
  94.     FILE *saveofp = Nullfp;
  95.     char savetype = ' ';
  96.  
  97.     mode[0] = mode[1] = mode[2] = '\0';
  98.     name = myname;
  99.     forkprocess = 1;        /* assume true if no fork */
  100.     while (len && isSPACE(name[len-1]))
  101.     name[--len] = '\0';
  102.     if (!io)
  103.     io = GvIO(gv) = newIO();
  104.     else if (io->ifp) {
  105.     fd = fileno(io->ifp);
  106.     if (io->type == '-')
  107.         result = 0;
  108.     else if (fd <= maxsysfd) {
  109.         saveifp = io->ifp;
  110.         saveofp = io->ofp;
  111.         savetype = io->type;
  112.         result = 0;
  113.     }
  114.     else if (io->type == '|')
  115.         result = my_pclose(io->ifp);
  116.     else if (io->ifp != io->ofp) {
  117.         if (io->ofp) {
  118.         result = fclose(io->ofp);
  119.         fclose(io->ifp);    /* clear stdio, fd already closed */
  120.         }
  121.         else
  122.         result = fclose(io->ifp);
  123.     }
  124.     else
  125.         result = fclose(io->ifp);
  126.     if (result == EOF && fd > maxsysfd)
  127.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  128.           GvENAME(gv));
  129.     io->ofp = io->ifp = Nullfp;
  130.     }
  131.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  132.     mode[1] = *name++;
  133.     mode[2] = '\0';
  134.     --len;
  135.     writing = 1;
  136.     }
  137.     else  {
  138.     mode[1] = '\0';
  139.     }
  140.     io->type = *name;
  141.     if (*name == '|') {
  142.     /*SUPPRESS 530*/
  143.     for (name++; isSPACE(*name); name++) ;
  144.     if (strNE(name,"-"))
  145.         TAINT_ENV();
  146.     TAINT_PROPER("piped open");
  147.     fp = my_popen(name,"w");
  148.     writing = 1;
  149.     }
  150.     else if (*name == '>') {
  151.     TAINT_PROPER("open");
  152.     name++;
  153.     if (*name == '>') {
  154.         mode[0] = io->type = 'a';
  155.         name++;
  156.     }
  157.     else
  158.         mode[0] = 'w';
  159.     writing = 1;
  160.     if (*name == '&') {
  161.       duplicity:
  162.         name++;
  163.         while (isSPACE(*name))
  164.         name++;
  165.         if (isDIGIT(*name))
  166.         fd = atoi(name);
  167.         else {
  168.         gv = gv_fetchpv(name,FALSE);
  169.         if (!gv || !GvIO(gv)) {
  170. #ifdef EINVAL
  171.             errno = EINVAL;
  172. #endif
  173.             goto say_false;
  174.         }
  175.         if (GvIO(gv) && GvIO(gv)->ifp) {
  176.             fd = fileno(GvIO(gv)->ifp);
  177.             if (GvIO(gv)->type == 's')
  178.             io->type = 's';
  179.         }
  180.         else
  181.             fd = -1;
  182.         }
  183.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  184.         close(fd);
  185.         }
  186.     }
  187.     else {
  188.         while (isSPACE(*name))
  189.         name++;
  190.         if (strEQ(name,"-")) {
  191.         fp = stdout;
  192.         io->type = '-';
  193.         }
  194.         else  {
  195.         fp = fopen(name,mode);
  196.         }
  197.     }
  198.     }
  199.     else {
  200.     if (*name == '<') {
  201.         mode[0] = 'r';
  202.         name++;
  203.         while (isSPACE(*name))
  204.         name++;
  205.         if (*name == '&')
  206.         goto duplicity;
  207.         if (strEQ(name,"-")) {
  208.         fp = stdin;
  209.         io->type = '-';
  210.         }
  211.         else
  212.         fp = fopen(name,mode);
  213.     }
  214.     else if (name[len-1] == '|') {
  215.         name[--len] = '\0';
  216.         while (len && isSPACE(name[len-1]))
  217.         name[--len] = '\0';
  218.         /*SUPPRESS 530*/
  219.         for (; isSPACE(*name); name++) ;
  220.         if (strNE(name,"-"))
  221.         TAINT_ENV();
  222.         TAINT_PROPER("piped open");
  223.         fp = my_popen(name,"r");
  224.         io->type = '|';
  225.     }
  226.     else {
  227.         io->type = '<';
  228.         /*SUPPRESS 530*/
  229.         for (; isSPACE(*name); name++) ;
  230.         if (strEQ(name,"-")) {
  231.         fp = stdin;
  232.         io->type = '-';
  233.         }
  234.         else
  235.         fp = fopen(name,"r");
  236.     }
  237.     }
  238.     if (!fp) {
  239.     if (dowarn && io->type == '<' && index(name, '\n'))
  240.         warn(warn_nl, "open");
  241.     Safefree(myname);
  242.     goto say_false;
  243.     }
  244.     Safefree(myname);
  245.     if (io->type &&
  246.       io->type != '|' && io->type != '-') {
  247.     if (fstat(fileno(fp),&statbuf) < 0) {
  248.         (void)fclose(fp);
  249.         goto say_false;
  250.     }
  251.     if (S_ISSOCK(statbuf.st_mode))
  252.         io->type = 's';    /* in case a socket was passed in to us */
  253. #ifdef HAS_SOCKET
  254.     else if (
  255. #ifdef S_IFMT
  256.         !(statbuf.st_mode & S_IFMT)
  257. #else
  258.         !statbuf.st_mode
  259. #endif
  260.     ) {
  261.         I32 buflen = sizeof tokenbuf;
  262.         if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
  263.         || errno != ENOTSOCK)
  264.         io->type = 's'; /* some OS's return 0 on fstat()ed socket */
  265.                 /* but some return 0 for streams too, sigh */
  266.     }
  267. #endif
  268.     }
  269.     if (saveifp) {        /* must use old fp? */
  270.     fd = fileno(saveifp);
  271.     if (saveofp) {
  272.         fflush(saveofp);        /* emulate fclose() */
  273.         if (saveofp != saveifp) {    /* was a socket? */
  274.         fclose(saveofp);
  275.         if (fd > 2)
  276.             Safefree(saveofp);
  277.         }
  278.     }
  279.     if (fd != fileno(fp)) {
  280.         int pid;
  281.         SV *sv;
  282.  
  283.         dup2(fileno(fp), fd);
  284.         sv = *av_fetch(fdpid,fileno(fp),TRUE);
  285.         pid = SvIV(sv);
  286.         SvIV(sv) = 0;
  287.         sv = *av_fetch(fdpid,fd,TRUE);
  288.         SvIV(sv) = pid;
  289.         fclose(fp);
  290.  
  291.     }
  292.     fp = saveifp;
  293.     clearerr(fp);
  294.     }
  295. #if defined(HAS_FCNTL) && defined(FFt_SETFD)
  296.     fd = fileno(fp);
  297.     fcntl(fd,FFt_SETFD,fd > maxsysfd);
  298. #endif
  299.     io->ifp = fp;
  300.     if (writing) {
  301.     if (io->type == 's'
  302.       || (io->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  303.         if (!(io->ofp = fdopen(fileno(fp),"w"))) {
  304.         fclose(fp);
  305.         io->ifp = Nullfp;
  306.         goto say_false;
  307.         }
  308.     }
  309.     else
  310.         io->ofp = fp;
  311.     }
  312.     return TRUE;
  313.  
  314. say_false:
  315.     io->ifp = saveifp;
  316.     io->ofp = saveofp;
  317.     io->type = savetype;
  318.     return FALSE;
  319. }
  320.  
  321. FILE *
  322. nextargv(gv)
  323. register GV *gv;
  324. {
  325.     register SV *sv;
  326. #ifndef FLEXFILENAMES
  327.     int filedev;
  328.     int fileino;
  329. #endif
  330.     int fileuid;
  331.     int filegid;
  332.  
  333.     if (!argvoutgv)
  334.     argvoutgv = gv_fetchpv("ARGVOUT",TRUE);
  335.     if (filemode & (S_ISUID|S_ISGID)) {
  336.     fflush(GvIO(argvoutgv)->ifp);  /* chmod must follow last write */
  337. #ifdef HAS_FCHMOD
  338.     (void)fchmod(lastfd,filemode);
  339. #else
  340.     (void)chmod(oldname,filemode);
  341. #endif
  342.     }
  343.     filemode = 0;
  344.     while (av_len(GvAV(gv)) >= 0) {
  345.     sv = av_shift(GvAV(gv));
  346.     sv_setsv(GvSV(gv),sv);
  347.     SvSETMAGIC(GvSV(gv));
  348.     oldname = SvPVnx(GvSV(gv));
  349.     if (do_open(gv,oldname,SvCUR(GvSV(gv)))) {
  350.         if (inplace) {
  351.         TAINT_PROPER("inplace open");
  352.         if (strEQ(oldname,"-")) {
  353.             sv_free(sv);
  354.             defoutgv = gv_fetchpv("STDOUT",TRUE);
  355.             return GvIO(gv)->ifp;
  356.         }
  357. #ifndef FLEXFILENAMES
  358.         filedev = statbuf.st_dev;
  359.         fileino = statbuf.st_ino;
  360. #endif
  361.         filemode = statbuf.st_mode;
  362.         fileuid = statbuf.st_uid;
  363.         filegid = statbuf.st_gid;
  364.         if (!S_ISREG(filemode)) {
  365.             warn("Can't do inplace edit: %s is not a regular file",
  366.               oldname );
  367.             do_close(gv,FALSE);
  368.             sv_free(sv);
  369.             continue;
  370.         }
  371.         if (*inplace) {
  372. #ifdef SUFFIX
  373.             add_suffix(sv,inplace);
  374. #else
  375.             sv_catpv(sv,inplace);
  376. #endif
  377. #ifndef FLEXFILENAMES
  378.             if (stat(SvPV(sv),&statbuf) >= 0
  379.               && statbuf.st_dev == filedev
  380.               && statbuf.st_ino == fileino ) {
  381.             warn("Can't do inplace edit: %s > 14 characters",
  382.               SvPV(sv) );
  383.             do_close(gv,FALSE);
  384.             sv_free(sv);
  385.             continue;
  386.             }
  387. #endif
  388. #ifdef HAS_RENAME
  389. #ifndef DOSISH
  390.             if (rename(oldname,SvPV(sv)) < 0) {
  391.             warn("Can't rename %s to %s: %s, skipping file",
  392.               oldname, SvPV(sv), strerror(errno) );
  393.             do_close(gv,FALSE);
  394.             sv_free(sv);
  395.             continue;
  396.             }
  397. #else
  398.             do_close(gv,FALSE);
  399.             (void)unlink(SvPV(sv));
  400.             (void)rename(oldname,SvPV(sv));
  401.             do_open(gv,SvPV(sv),SvCUR(GvSV(gv)));
  402. #endif /* MSDOS */
  403. #else
  404.             (void)UNLINK(SvPV(sv));
  405.             if (link(oldname,SvPV(sv)) < 0) {
  406.             warn("Can't rename %s to %s: %s, skipping file",
  407.               oldname, SvPV(sv), strerror(errno) );
  408.             do_close(gv,FALSE);
  409.             sv_free(sv);
  410.             continue;
  411.             }
  412.             (void)UNLINK(oldname);
  413. #endif
  414.         }
  415.         else {
  416. #ifndef DOSISH
  417.             if (UNLINK(oldname) < 0) {
  418.             warn("Can't rename %s to %s: %s, skipping file",
  419.               oldname, SvPV(sv), strerror(errno) );
  420.             do_close(gv,FALSE);
  421.             sv_free(sv);
  422.             continue;
  423.             }
  424. #else
  425.             fatal("Can't do inplace edit without backup");
  426. #endif
  427.         }
  428.  
  429.         sv_setpvn(sv,">",1);
  430.         sv_catpv(sv,oldname);
  431.         errno = 0;        /* in case sprintf set errno */
  432.         if (!do_open(argvoutgv,SvPV(sv),SvCUR(sv))) {
  433.             warn("Can't do inplace edit on %s: %s",
  434.               oldname, strerror(errno) );
  435.             do_close(gv,FALSE);
  436.             sv_free(sv);
  437.             continue;
  438.         }
  439.         defoutgv = argvoutgv;
  440.         lastfd = fileno(GvIO(argvoutgv)->ifp);
  441.         (void)fstat(lastfd,&statbuf);
  442. #ifdef HAS_FCHMOD
  443.         (void)fchmod(lastfd,filemode);
  444. #else
  445.         (void)chmod(oldname,filemode);
  446. #endif
  447.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  448. #ifdef HAS_FCHOWN
  449.             (void)fchown(lastfd,fileuid,filegid);
  450. #else
  451. #ifdef HAS_CHOWN
  452.             (void)chown(oldname,fileuid,filegid);
  453. #endif
  454. #endif
  455.         }
  456.         }
  457.         sv_free(sv);
  458.         return GvIO(gv)->ifp;
  459.     }
  460.     else
  461.         fprintf(stderr,"Can't open %s: %s\n",SvPVn(sv), strerror(errno));
  462.     sv_free(sv);
  463.     }
  464.     if (inplace) {
  465.     (void)do_close(argvoutgv,FALSE);
  466.     defoutgv = gv_fetchpv("STDOUT",TRUE);
  467.     }
  468.     return Nullfp;
  469. }
  470.  
  471. #ifdef HAS_PIPE
  472. void
  473. do_pipe(sv, rgv, wgv)
  474. SV *sv;
  475. GV *rgv;
  476. GV *wgv;
  477. {
  478.     register IO *rstio;
  479.     register IO *wstio;
  480.     int fd[2];
  481.  
  482.     if (!rgv)
  483.     goto badexit;
  484.     if (!wgv)
  485.     goto badexit;
  486.  
  487.     rstio = GvIO(rgv);
  488.     wstio = GvIO(wgv);
  489.  
  490.     if (!rstio)
  491.     rstio = GvIO(rgv) = newIO();
  492.     else if (rstio->ifp)
  493.     do_close(rgv,FALSE);
  494.     if (!wstio)
  495.     wstio = GvIO(wgv) = newIO();
  496.     else if (wstio->ifp)
  497.     do_close(wgv,FALSE);
  498.  
  499.     if (pipe(fd) < 0)
  500.     goto badexit;
  501.     rstio->ifp = fdopen(fd[0], "r");
  502.     wstio->ofp = fdopen(fd[1], "w");
  503.     wstio->ifp = wstio->ofp;
  504.     rstio->type = '<';
  505.     wstio->type = '>';
  506.     if (!rstio->ifp || !wstio->ofp) {
  507.     if (rstio->ifp) fclose(rstio->ifp);
  508.     else close(fd[0]);
  509.     if (wstio->ofp) fclose(wstio->ofp);
  510.     else close(fd[1]);
  511.     goto badexit;
  512.     }
  513.  
  514.     sv_setsv(sv,&sv_yes);
  515.     return;
  516.  
  517. badexit:
  518.     sv_setsv(sv,&sv_undef);
  519.     return;
  520. }
  521. #endif
  522.  
  523. bool
  524. do_close(gv,explicit)
  525. GV *gv;
  526. bool explicit;
  527. {
  528.     bool retval = FALSE;
  529.     register IO *io;
  530.     int status;
  531.  
  532.     if (!gv)
  533.     gv = argvgv;
  534.     if (!gv) {
  535.     errno = EBADF;
  536.     return FALSE;
  537.     }
  538.     io = GvIO(gv);
  539.     if (!io) {        /* never opened */
  540.     if (dowarn && explicit)
  541.         warn("Close on unopened file <%s>",GvENAME(gv));
  542.     return FALSE;
  543.     }
  544.     if (io->ifp) {
  545.     if (io->type == '|') {
  546.         status = my_pclose(io->ifp);
  547.         retval = (status == 0);
  548.         statusvalue = (unsigned short)status & 0xffff;
  549.     }
  550.     else if (io->type == '-')
  551.         retval = TRUE;
  552.     else {
  553.         if (io->ofp && io->ofp != io->ifp) {        /* a socket */
  554.         retval = (fclose(io->ofp) != EOF);
  555.         fclose(io->ifp);    /* clear stdio, fd already closed */
  556.         }
  557.         else
  558.         retval = (fclose(io->ifp) != EOF);
  559.     }
  560.     io->ofp = io->ifp = Nullfp;
  561.     }
  562.     if (explicit) {
  563.     io->lines = 0;
  564.     io->page = 0;
  565.     io->lines_left = io->page_len;
  566.     }
  567.     io->type = ' ';
  568.     return retval;
  569. }
  570.  
  571. bool
  572. do_eof(gv)
  573. GV *gv;
  574. {
  575.     register IO *io;
  576.     int ch;
  577.  
  578.     io = GvIO(gv);
  579.  
  580.     if (!io)
  581.     return TRUE;
  582.  
  583.     while (io->ifp) {
  584.  
  585. #ifdef STDSTDIO            /* (the code works without this) */
  586.     if (io->ifp->_cnt > 0)    /* cheat a little, since */
  587.         return FALSE;        /* this is the most usual case */
  588. #endif
  589.  
  590.     ch = getc(io->ifp);
  591.     if (ch != EOF) {
  592.         (void)ungetc(ch, io->ifp);
  593.         return FALSE;
  594.     }
  595. #ifdef STDSTDIO
  596.     if (io->ifp->_cnt < -1)
  597.         io->ifp->_cnt = -1;
  598. #endif
  599.     if (gv == argvgv) {        /* not necessarily a real EOF yet? */
  600.         if (!nextargv(argvgv))    /* get another fp handy */
  601.         return TRUE;
  602.     }
  603.     else
  604.         return TRUE;        /* normal fp, definitely end of file */
  605.     }
  606.     return TRUE;
  607. }
  608.  
  609. long
  610. do_tell(gv)
  611. GV *gv;
  612. {
  613.     register IO *io;
  614.  
  615.     if (!gv)
  616.     goto phooey;
  617.  
  618.     io = GvIO(gv);
  619.     if (!io || !io->ifp)
  620.     goto phooey;
  621.  
  622. #ifdef ULTRIX_STDIO_BOTCH
  623.     if (feof(io->ifp))
  624.     (void)fseek (io->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  625. #endif
  626.  
  627.     return ftell(io->ifp);
  628.  
  629. phooey:
  630.     if (dowarn)
  631.     warn("tell() on unopened file");
  632.     errno = EBADF;
  633.     return -1L;
  634. }
  635.  
  636. bool
  637. do_seek(gv, pos, whence)
  638. GV *gv;
  639. long pos;
  640. int whence;
  641. {
  642.     register IO *io;
  643.  
  644.     if (!gv)
  645.     goto nuts;
  646.  
  647.     io = GvIO(gv);
  648.     if (!io || !io->ifp)
  649.     goto nuts;
  650.  
  651. #ifdef ULTRIX_STDIO_BOTCH
  652.     if (feof(io->ifp))
  653.     (void)fseek (io->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  654. #endif
  655.  
  656.     return fseek(io->ifp, pos, whence) >= 0;
  657.  
  658. nuts:
  659.     if (dowarn)
  660.     warn("seek() on unopened file");
  661.     errno = EBADF;
  662.     return FALSE;
  663. }
  664.  
  665. I32
  666. do_ctl(optype,gv,func,argstr)
  667. I32 optype;
  668. GV *gv;
  669. I32 func;
  670. SV *argstr;
  671. {
  672.     register IO *io;
  673.     register char *s;
  674.     I32 retval;
  675.  
  676.     if (!gv || !argstr || !(io = GvIO(gv)) || !io->ifp) {
  677.     errno = EBADF;    /* well, sort of... */
  678.     return -1;
  679.     }
  680.  
  681.     if (SvPOK(argstr) || !SvNIOK(argstr)) {
  682.     if (!SvPOK(argstr))
  683.         s = SvPVn(argstr);
  684.  
  685. #ifdef IOCPARM_MASK
  686. #ifndef IOCPARM_LEN
  687. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  688. #endif
  689. #endif
  690. #ifdef IOCPARM_LEN
  691.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  692. #else
  693.     retval = 256;            /* otherwise guess at what's safe */
  694. #endif
  695.     if (SvCUR(argstr) < retval) {
  696.         Sv_Grow(argstr,retval+1);
  697.         SvCUR_set(argstr, retval);
  698.     }
  699.  
  700.     s = SvPV(argstr);
  701.     s[SvCUR(argstr)] = 17;    /* a little sanity check here */
  702.     }
  703.     else {
  704.     retval = SvIVn(argstr);
  705. #ifdef DOSISH
  706.     s = (char*)(long)retval;        /* ouch */
  707. #else
  708.     s = (char*)retval;        /* ouch */
  709. #endif
  710.     }
  711.  
  712. #ifndef lint
  713.     if (optype == OP_IOCTL)
  714.     retval = ioctl(fileno(io->ifp), func, s);
  715.     else
  716. #ifdef DOSISH
  717.     fatal("fcntl is not implemented");
  718. #else
  719. #ifdef HAS_FCNTL
  720.     retval = fcntl(fileno(io->ifp), func, s);
  721. #else
  722.     fatal("fcntl is not implemented");
  723. #endif
  724. #endif
  725. #else /* lint */
  726.     retval = 0;
  727. #endif /* lint */
  728.  
  729.     if (SvPOK(argstr)) {
  730.     if (s[SvCUR(argstr)] != 17)
  731.         fatal("Return value overflowed string");
  732.     s[SvCUR(argstr)] = 0;        /* put our null back */
  733.     }
  734.     return retval;
  735. }
  736.  
  737. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(FFt_FREESP)
  738.     /* code courtesy of William Kucharski */
  739. #define HAS_CHSIZE
  740.  
  741. I32 chsize(fd, length)
  742. I32 fd;            /* file descriptor */
  743. off_t length;        /* length to set file to */
  744. {
  745.     extern long lseek();
  746.     struct flock fl;
  747.     struct stat filebuf;
  748.  
  749.     if (fstat(fd, &filebuf) < 0)
  750.     return -1;
  751.  
  752.     if (filebuf.st_size < length) {
  753.  
  754.     /* extend file length */
  755.  
  756.     if ((lseek(fd, (length - 1), 0)) < 0)
  757.         return -1;
  758.  
  759.     /* write a "0" byte */
  760.  
  761.     if ((write(fd, "", 1)) != 1)
  762.         return -1;
  763.     }
  764.     else {
  765.     /* truncate length */
  766.  
  767.     fl.l_whence = 0;
  768.     fl.l_len = 0;
  769.     fl.l_start = length;
  770.     fl.l_type = FFt_WRLCK;    /* write lock on file space */
  771.  
  772.     /*
  773.     * This relies on the UNDOCUMENTED FFt_FREESP argument to
  774.     * fcntl(2), which truncates the file so that it ends at the
  775.     * position indicated by fl.l_start.
  776.     *
  777.     * Will minor miracles never cease?
  778.     */
  779.  
  780.     if (fcntl(fd, FFt_FREESP, &fl) < 0)
  781.         return -1;
  782.  
  783.     }
  784.  
  785.     return 0;
  786. }
  787. #endif /* FFt_FREESP */
  788.  
  789. I32
  790. looks_like_number(sv)
  791. SV *sv;
  792. {
  793.     register char *s;
  794.     register char *send;
  795.  
  796.     if (!SvPOK(sv))
  797.     return TRUE;
  798.     s = SvPV(sv); 
  799.     send = s + SvCUR(sv);
  800.     while (isSPACE(*s))
  801.     s++;
  802.     if (s >= send)
  803.     return FALSE;
  804.     if (*s == '+' || *s == '-')
  805.     s++;
  806.     while (isDIGIT(*s))
  807.     s++;
  808.     if (s == send)
  809.     return TRUE;
  810.     if (*s == '.') 
  811.     s++;
  812.     else if (s == SvPV(sv))
  813.     return FALSE;
  814.     while (isDIGIT(*s))
  815.     s++;
  816.     if (s == send)
  817.     return TRUE;
  818.     if (*s == 'e' || *s == 'E') {
  819.     s++;
  820.     if (*s == '+' || *s == '-')
  821.         s++;
  822.     while (isDIGIT(*s))
  823.         s++;
  824.     }
  825.     while (isSPACE(*s))
  826.     s++;
  827.     if (s >= send)
  828.     return TRUE;
  829.     return FALSE;
  830. }
  831.  
  832. bool
  833. do_print(sv,fp)
  834. register SV *sv;
  835. FILE *fp;
  836. {
  837.     register char *tmps;
  838.     SV* tmpstr;
  839.  
  840.     /* assuming fp is checked earlier */
  841.     if (!sv)
  842.     return TRUE;
  843.     if (ofmt) {
  844.     if (SvMAGICAL(sv))
  845.         mg_get(sv);
  846.         if (SvIOK(sv) && SvIV(sv) != 0) {
  847.         fprintf(fp, ofmt, (double)SvIV(sv));
  848.         return !ferror(fp);
  849.     }
  850.     if (  (SvNOK(sv) && SvNV(sv) != 0.0)
  851.        || (looks_like_number(sv) && sv_2nv(sv) != 0.0) ) {
  852.         fprintf(fp, ofmt, SvNV(sv));
  853.         return !ferror(fp);
  854.     }
  855.     }
  856.     switch (SvTYPE(sv)) {
  857.     case SVt_NULL:
  858.     return TRUE;
  859.     case SVt_REF:
  860.     fprintf(fp, "%s", sv_2pv(sv));
  861.     return !ferror(fp);
  862.     case SVt_IV:
  863.     if (SvMAGICAL(sv))
  864.         mg_get(sv);
  865.     fprintf(fp, "%d", SvIV(sv));
  866.     return !ferror(fp);
  867.     default:
  868.     tmps = SvPVn(sv);
  869.     break;
  870.     }
  871.     if (SvCUR(sv) && (fwrite(tmps,1,SvCUR(sv),fp) == 0 || ferror(fp)))
  872.     return FALSE;
  873.     return TRUE;
  874. }
  875.  
  876. I32
  877. my_stat(ARGS)
  878. dARGS
  879. {
  880.     dSP;
  881.     IO *io;
  882.  
  883.     if (op->op_flags & OPf_SPECIAL) {
  884.     EXTEND(sp,1);
  885.     io = GvIO(cGVOP->op_gv);
  886.     if (io && io->ifp) {
  887.         statgv = cGVOP->op_gv;
  888.         sv_setpv(statname,"");
  889.         laststype = OP_STAT;
  890.         return (laststatval = fstat(fileno(io->ifp), &statcache));
  891.     }
  892.     else {
  893.         if (cGVOP->op_gv == defgv)
  894.         return laststatval;
  895.         if (dowarn)
  896.         warn("Stat on unopened file <%s>",
  897.           GvENAME(cGVOP->op_gv));
  898.         statgv = Nullgv;
  899.         sv_setpv(statname,"");
  900.         return (laststatval = -1);
  901.     }
  902.     }
  903.     else {
  904.     dPOPss;
  905.     PUTBACK;
  906.     statgv = Nullgv;
  907.     sv_setpv(statname,SvPVn(sv));
  908.     laststype = OP_STAT;
  909.     laststatval = stat(SvPVn(sv),&statcache);
  910.     if (laststatval < 0 && dowarn && index(SvPVn(sv), '\n'))
  911.         warn(warn_nl, "stat");
  912.     return laststatval;
  913.     }
  914. }
  915.  
  916. I32
  917. my_lstat(ARGS)
  918. dARGS
  919. {
  920.     dSP;
  921.     SV *sv;
  922.     if (op->op_flags & OPf_SPECIAL) {
  923.     EXTEND(sp,1);
  924.     if (cGVOP->op_gv == defgv) {
  925.         if (laststype != OP_LSTAT)
  926.         fatal("The stat preceding -l _ wasn't an lstat");
  927.         return laststatval;
  928.     }
  929.     fatal("You can't use -l on a filehandle");
  930.     }
  931.  
  932.     laststype = OP_LSTAT;
  933.     statgv = Nullgv;
  934.     sv = POPs;
  935.     PUTBACK;
  936.     sv_setpv(statname,SvPVn(sv));
  937. #ifdef HAS_LSTAT
  938.     laststatval = lstat(SvPVn(sv),&statcache);
  939. #else
  940.     laststatval = stat(SvPVn(sv),&statcache);
  941. #endif
  942.     if (laststatval < 0 && dowarn && index(SvPVn(sv), '\n'))
  943.     warn(warn_nl, "lstat");
  944.     return laststatval;
  945. }
  946.  
  947. bool
  948. do_aexec(really,mark,sp)
  949. SV *really;
  950. register SV **mark;
  951. register SV **sp;
  952. {
  953.     register char **a;
  954.     char *tmps;
  955.  
  956.     if (sp > mark) {
  957.     New(401,Argv, sp - mark + 1, char*);
  958.     a = Argv;
  959.     while (++mark <= sp) {
  960.         if (*mark)
  961.         *a++ = SvPVnx(*mark);
  962.         else
  963.         *a++ = "";
  964.     }
  965.     *a = Nullch;
  966.     if (*Argv[0] != '/')    /* will execvp use PATH? */
  967.         TAINT_ENV();        /* testing IFS here is overkill, probably */
  968.     if (really && *(tmps = SvPVn(really)))
  969.         execvp(tmps,Argv);
  970.     else
  971.         execvp(Argv[0],Argv);
  972.     }
  973.     do_execfree();
  974.     return FALSE;
  975. }
  976.  
  977. void
  978. do_execfree()
  979. {
  980.     if (Argv) {
  981.     Safefree(Argv);
  982.     Argv = Null(char **);
  983.     }
  984.     if (Cmd) {
  985.     Safefree(Cmd);
  986.     Cmd = Nullch;
  987.     }
  988. }
  989.  
  990. bool
  991. do_exec(cmd)
  992. char *cmd;
  993. {
  994.     register char **a;
  995.     register char *s;
  996.     char flags[10];
  997.  
  998.     /* save an extra exec if possible */
  999.  
  1000. #ifdef CSH
  1001.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1002.     strcpy(flags,"-c");
  1003.     s = cmd+cshlen+3;
  1004.     if (*s == 'f') {
  1005.         s++;
  1006.         strcat(flags,"f");
  1007.     }
  1008.     if (*s == ' ')
  1009.         s++;
  1010.     if (*s++ == '\'') {
  1011.         char *ncmd = s;
  1012.  
  1013.         while (*s)
  1014.         s++;
  1015.         if (s[-1] == '\n')
  1016.         *--s = '\0';
  1017.         if (s[-1] == '\'') {
  1018.         *--s = '\0';
  1019.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1020.         *s = '\'';
  1021.         return FALSE;
  1022.         }
  1023.     }
  1024.     }
  1025. #endif /* CSH */
  1026.  
  1027.     /* see if there are shell metacharacters in it */
  1028.  
  1029.     /*SUPPRESS 530*/
  1030.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1031.     if (*s == '=')
  1032.     goto doshell;
  1033.     for (s = cmd; *s; s++) {
  1034.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1035.         if (*s == '\n' && !s[1]) {
  1036.         *s = '\0';
  1037.         break;
  1038.         }
  1039.       doshell:
  1040.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1041.         return FALSE;
  1042.     }
  1043.     }
  1044.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1045.     Cmd = nsavestr(cmd, s-cmd);
  1046.     a = Argv;
  1047.     for (s = Cmd; *s;) {
  1048.     while (*s && isSPACE(*s)) s++;
  1049.     if (*s)
  1050.         *(a++) = s;
  1051.     while (*s && !isSPACE(*s)) s++;
  1052.     if (*s)
  1053.         *s++ = '\0';
  1054.     }
  1055.     *a = Nullch;
  1056.     if (Argv[0]) {
  1057.     execvp(Argv[0],Argv);
  1058.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1059.         do_execfree();
  1060.         goto doshell;
  1061.     }
  1062.     }
  1063.     do_execfree();
  1064.     return FALSE;
  1065. }
  1066.  
  1067. I32
  1068. apply(type,mark,sp)
  1069. I32 type;
  1070. register SV **mark;
  1071. register SV **sp;
  1072. {
  1073.     register I32 val;
  1074.     register I32 val2;
  1075.     register I32 tot = 0;
  1076.     char *s;
  1077.     SV **oldmark = mark;
  1078.  
  1079. #ifdef TAINT
  1080.     while (++mark <= sp)
  1081.     TAINT_IF((*mark)->sv_tainted);
  1082.     mark = oldmark;
  1083. #endif
  1084.     switch (type) {
  1085.     case OP_CHMOD:
  1086.     TAINT_PROPER("chmod");
  1087.     if (++mark <= sp) {
  1088.         tot = sp - mark;
  1089.         val = SvIVnx(*mark);
  1090.         while (++mark <= sp) {
  1091.         if (chmod(SvPVnx(*mark),val))
  1092.             tot--;
  1093.         }
  1094.     }
  1095.     break;
  1096. #ifdef HAS_CHOWN
  1097.     case OP_CHOWN:
  1098.     TAINT_PROPER("chown");
  1099.     if (sp - mark > 2) {
  1100.         tot = sp - mark;
  1101.         val = SvIVnx(*++mark);
  1102.         val2 = SvIVnx(*++mark);
  1103.         while (++mark <= sp) {
  1104.         if (chown(SvPVnx(*mark),val,val2))
  1105.             tot--;
  1106.         }
  1107.     }
  1108.     break;
  1109. #endif
  1110. #ifdef HAS_KILL
  1111.     case OP_KILL:
  1112.     TAINT_PROPER("kill");
  1113.     s = SvPVnx(*++mark);
  1114.     tot = sp - mark;
  1115.     if (isUPPER(*s)) {
  1116.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  1117.         s += 3;
  1118.         if (!(val = whichsig(s)))
  1119.         fatal("Unrecognized signal name \"%s\"",s);
  1120.     }
  1121.     else
  1122.         val = SvIVnx(*mark);
  1123.     if (val < 0) {
  1124.         val = -val;
  1125.         while (++mark <= sp) {
  1126.         I32 proc = SvIVnx(*mark);
  1127. #ifdef HAS_KILLPG
  1128.         if (killpg(proc,val))    /* BSD */
  1129. #else
  1130.         if (kill(-proc,val))    /* SYSV */
  1131. #endif
  1132.             tot--;
  1133.         }
  1134.     }
  1135.     else {
  1136.         while (++mark <= sp) {
  1137.         if (kill(SvIVnx(*mark),val))
  1138.             tot--;
  1139.         }
  1140.     }
  1141.     break;
  1142. #endif
  1143.     case OP_UNLINK:
  1144.     TAINT_PROPER("unlink");
  1145.     tot = sp - mark;
  1146.     while (++mark <= sp) {
  1147.         s = SvPVnx(*mark);
  1148.         if (euid || unsafe) {
  1149.         if (UNLINK(s))
  1150.             tot--;
  1151.         }
  1152.         else {    /* don't let root wipe out directories without -U */
  1153. #ifdef HAS_LSTAT
  1154.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  1155. #else
  1156.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  1157. #endif
  1158.             tot--;
  1159.         else {
  1160.             if (UNLINK(s))
  1161.             tot--;
  1162.         }
  1163.         }
  1164.     }
  1165.     break;
  1166.     case OP_UTIME:
  1167.     TAINT_PROPER("utime");
  1168.     if (sp - mark > 2) {
  1169. #ifdef I_UTIME
  1170.         struct utimbuf utbuf;
  1171. #else
  1172.         struct {
  1173.         long    actime;
  1174.         long    modtime;
  1175.         } utbuf;
  1176. #endif
  1177.  
  1178.         Zero(&utbuf, sizeof utbuf, char);
  1179.         utbuf.actime = SvIVnx(*++mark);    /* time accessed */
  1180.         utbuf.modtime = SvIVnx(*++mark);    /* time modified */
  1181.         tot = sp - mark;
  1182.         while (++mark <= sp) {
  1183.         if (utime(SvPVnx(*mark),&utbuf))
  1184.             tot--;
  1185.         }
  1186.     }
  1187.     else
  1188.         tot = 0;
  1189.     break;
  1190.     }
  1191.     return tot;
  1192. }
  1193.  
  1194. /* Do the permissions allow some operation?  Assumes statcache already set. */
  1195.  
  1196. I32
  1197. cando(bit, effective, statbufp)
  1198. I32 bit;
  1199. I32 effective;
  1200. register struct stat *statbufp;
  1201. {
  1202. #ifdef DOSISH
  1203.     /* [Comments and code from Len Reed]
  1204.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  1205.      * to write-protected files.  The execute permission bit is set
  1206.      * by the Miscrosoft C library stat() function for the following:
  1207.      *        .exe files
  1208.      *        .com files
  1209.      *        .bat files
  1210.      *        directories
  1211.      * All files and directories are readable.
  1212.      * Directories and special files, e.g. "CON", cannot be
  1213.      * write-protected.
  1214.      * [Comment by Tom Dinger -- a directory can have the write-protect
  1215.      *        bit set in the file system, but DOS permits changes to
  1216.      *        the directory anyway.  In addition, all bets are off
  1217.      *        here for networked software, such as Novell and
  1218.      *        Sun's PC-NFS.]
  1219.      */
  1220.  
  1221.      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
  1222.       * too so it will actually look into the files for magic numbers
  1223.       */
  1224.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  1225.  
  1226. #else /* ! MSDOS */
  1227.     if ((effective ? euid : uid) == 0) {    /* root is special */
  1228.     if (bit == S_IXUSR) {
  1229.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  1230.         return TRUE;
  1231.     }
  1232.     else
  1233.         return TRUE;        /* root reads and writes anything */
  1234.     return FALSE;
  1235.     }
  1236.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  1237.     if (statbufp->st_mode & bit)
  1238.         return TRUE;    /* ok as "user" */
  1239.     }
  1240.     else if (ingroup((I32)statbufp->st_gid,effective)) {
  1241.     if (statbufp->st_mode & bit >> 3)
  1242.         return TRUE;    /* ok as "group" */
  1243.     }
  1244.     else if (statbufp->st_mode & bit >> 6)
  1245.     return TRUE;    /* ok as "other" */
  1246.     return FALSE;
  1247. #endif /* ! MSDOS */
  1248. }
  1249.  
  1250. I32
  1251. ingroup(testgid,effective)
  1252. I32 testgid;
  1253. I32 effective;
  1254. {
  1255.     if (testgid == (effective ? egid : gid))
  1256.     return TRUE;
  1257. #ifdef HAS_GETGROUPS
  1258. #ifndef NGROUPS
  1259. #define NGROUPS 32
  1260. #endif
  1261.     {
  1262.     GROUPSTYPE gary[NGROUPS];
  1263.     I32 anum;
  1264.  
  1265.     anum = getgroups(NGROUPS,gary);
  1266.     while (--anum >= 0)
  1267.         if (gary[anum] == testgid)
  1268.         return TRUE;
  1269.     }
  1270. #endif
  1271.     return FALSE;
  1272. }
  1273.  
  1274. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  1275.  
  1276. I32
  1277. do_ipcget(optype, mark, sp)
  1278. I32 optype;
  1279. SV **mark;
  1280. SV **sp;
  1281. {
  1282.     key_t key;
  1283.     I32 n, flags;
  1284.  
  1285.     key = (key_t)SvNVnx(*++mark);
  1286.     n = (optype == OP_MSGGET) ? 0 : SvIVnx(*++mark);
  1287.     flags = SvIVnx(*++mark);
  1288.     errno = 0;
  1289.     switch (optype)
  1290.     {
  1291. #ifdef HAS_MSG
  1292.     case OP_MSGGET:
  1293.     return msgget(key, flags);
  1294. #endif
  1295. #ifdef HAS_SEM
  1296.     case OP_SEMGET:
  1297.     return semget(key, n, flags);
  1298. #endif
  1299. #ifdef HAS_SHM
  1300.     case OP_SHMGET:
  1301.     return shmget(key, n, flags);
  1302. #endif
  1303. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  1304.     default:
  1305.     fatal("%s not implemented", op_name[optype]);
  1306. #endif
  1307.     }
  1308.     return -1;            /* should never happen */
  1309. }
  1310.  
  1311. I32
  1312. do_ipcctl(optype, mark, sp)
  1313. I32 optype;
  1314. SV **mark;
  1315. SV **sp;
  1316. {
  1317.     SV *astr;
  1318.     char *a;
  1319.     I32 id, n, cmd, infosize, getinfo, ret;
  1320.  
  1321.     id = SvIVnx(*++mark);
  1322.     n = (optype == OP_SEMCTL) ? SvIVnx(*++mark) : 0;
  1323.     cmd = SvIVnx(*++mark);
  1324.     astr = *++mark;
  1325.     infosize = 0;
  1326.     getinfo = (cmd == IPC_STAT);
  1327.  
  1328.     switch (optype)
  1329.     {
  1330. #ifdef HAS_MSG
  1331.     case OP_MSGCTL:
  1332.     if (cmd == IPC_STAT || cmd == IPC_SET)
  1333.         infosize = sizeof(struct msqid_ds);
  1334.     break;
  1335. #endif
  1336. #ifdef HAS_SHM
  1337.     case OP_SHMCTL:
  1338.     if (cmd == IPC_STAT || cmd == IPC_SET)
  1339.         infosize = sizeof(struct shmid_ds);
  1340.     break;
  1341. #endif
  1342. #ifdef HAS_SEM
  1343.     case OP_SEMCTL:
  1344.     if (cmd == IPC_STAT || cmd == IPC_SET)
  1345.         infosize = sizeof(struct semid_ds);
  1346.     else if (cmd == GETALL || cmd == SETALL)
  1347.     {
  1348.         struct semid_ds semds;
  1349.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  1350.         return -1;
  1351.         getinfo = (cmd == GETALL);
  1352.         infosize = semds.sem_nsems * sizeof(short);
  1353.         /* "short" is technically wrong but much more portable
  1354.            than guessing about u_?short(_t)? */
  1355.     }
  1356.     break;
  1357. #endif
  1358. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  1359.     default:
  1360.     fatal("%s not implemented", op_name[optype]);
  1361. #endif
  1362.     }
  1363.  
  1364.     if (infosize)
  1365.     {
  1366.     if (getinfo)
  1367.     {
  1368.         SvGROW(astr, infosize+1);
  1369.         a = SvPVn(astr);
  1370.     }
  1371.     else
  1372.     {
  1373.         a = SvPVn(astr);
  1374.         if (SvCUR(astr) != infosize)
  1375.         {
  1376.         errno = EINVAL;
  1377.         return -1;
  1378.         }
  1379.     }
  1380.     }
  1381.     else
  1382.     {
  1383.     I32 i = SvIVn(astr);
  1384.     a = (char *)i;        /* ouch */
  1385.     }
  1386.     errno = 0;
  1387.     switch (optype)
  1388.     {
  1389. #ifdef HAS_MSG
  1390.     case OP_MSGCTL:
  1391.     ret = msgctl(id, cmd, (struct msqid_ds *)a);
  1392.     break;
  1393. #endif
  1394. #ifdef HAS_SEM
  1395.     case OP_SEMCTL:
  1396.     ret = semctl(id, n, cmd, (struct semid_ds *)a);
  1397.     break;
  1398. #endif
  1399. #ifdef HAS_SHM
  1400.     case OP_SHMCTL:
  1401.     ret = shmctl(id, cmd, (struct shmid_ds *)a);
  1402.     break;
  1403. #endif
  1404.     }
  1405.     if (getinfo && ret >= 0) {
  1406.     SvCUR_set(astr, infosize);
  1407.     *SvEND(astr) = '\0';
  1408.     }
  1409.     return ret;
  1410. }
  1411.  
  1412. I32
  1413. do_msgsnd(mark, sp)
  1414. SV **mark;
  1415. SV **sp;
  1416. {
  1417. #ifdef HAS_MSG
  1418.     SV *mstr;
  1419.     char *mbuf;
  1420.     I32 id, msize, flags;
  1421.  
  1422.     id = SvIVnx(*++mark);
  1423.     mstr = *++mark;
  1424.     flags = SvIVnx(*++mark);
  1425.     mbuf = SvPVn(mstr);
  1426.     if ((msize = SvCUR(mstr) - sizeof(long)) < 0) {
  1427.     errno = EINVAL;
  1428.     return -1;
  1429.     }
  1430.     errno = 0;
  1431.     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
  1432. #else
  1433.     fatal("msgsnd not implemented");
  1434. #endif
  1435. }
  1436.  
  1437. I32
  1438. do_msgrcv(mark, sp)
  1439. SV **mark;
  1440. SV **sp;
  1441. {
  1442. #ifdef HAS_MSG
  1443.     SV *mstr;
  1444.     char *mbuf;
  1445.     long mtype;
  1446.     I32 id, msize, flags, ret;
  1447.  
  1448.     id = SvIVnx(*++mark);
  1449.     mstr = *++mark;
  1450.     msize = SvIVnx(*++mark);
  1451.     mtype = (long)SvIVnx(*++mark);
  1452.     flags = SvIVnx(*++mark);
  1453.     mbuf = SvPVn(mstr);
  1454.     if (SvCUR(mstr) < sizeof(long)+msize+1) {
  1455.     SvGROW(mstr, sizeof(long)+msize+1);
  1456.     mbuf = SvPVn(mstr);
  1457.     }
  1458.     errno = 0;
  1459.     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
  1460.     if (ret >= 0) {
  1461.     SvCUR_set(mstr, sizeof(long)+ret);
  1462.     *SvEND(mstr) = '\0';
  1463.     }
  1464.     return ret;
  1465. #else
  1466.     fatal("msgrcv not implemented");
  1467. #endif
  1468. }
  1469.  
  1470. I32
  1471. do_semop(mark, sp)
  1472. SV **mark;
  1473. SV **sp;
  1474. {
  1475. #ifdef HAS_SEM
  1476.     SV *opstr;
  1477.     char *opbuf;
  1478.     I32 id, opsize;
  1479.  
  1480.     id = SvIVnx(*++mark);
  1481.     opstr = *++mark;
  1482.     opbuf = SvPVn(opstr);
  1483.     opsize = SvCUR(opstr);
  1484.     if (opsize < sizeof(struct sembuf)
  1485.     || (opsize % sizeof(struct sembuf)) != 0) {
  1486.     errno = EINVAL;
  1487.     return -1;
  1488.     }
  1489.     errno = 0;
  1490.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  1491. #else
  1492.     fatal("semop not implemented");
  1493. #endif
  1494. }
  1495.  
  1496. I32
  1497. do_shmio(optype, mark, sp)
  1498. I32 optype;
  1499. SV **mark;
  1500. SV **sp;
  1501. {
  1502. #ifdef HAS_SHM
  1503.     SV *mstr;
  1504.     char *mbuf, *shm;
  1505.     I32 id, mpos, msize;
  1506.     struct shmid_ds shmds;
  1507. #ifndef VOIDSHMAT
  1508.     extern char *shmat();
  1509. #endif
  1510.  
  1511.     id = SvIVnx(*++mark);
  1512.     mstr = *++mark;
  1513.     mpos = SvIVnx(*++mark);
  1514.     msize = SvIVnx(*++mark);
  1515.     errno = 0;
  1516.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  1517.     return -1;
  1518.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  1519.     errno = EFAULT;        /* can't do as caller requested */
  1520.     return -1;
  1521.     }
  1522.     shm = (char*)shmat(id, (char*)NULL, (optype == OP_SHMREAD) ? SHM_RDONLY : 0);
  1523.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  1524.     return -1;
  1525.     mbuf = SvPVn(mstr);
  1526.     if (optype == OP_SHMREAD) {
  1527.     if (SvCUR(mstr) < msize) {
  1528.         SvGROW(mstr, msize+1);
  1529.         mbuf = SvPVn(mstr);
  1530.     }
  1531.     Copy(shm + mpos, mbuf, msize, char);
  1532.     SvCUR_set(mstr, msize);
  1533.     *SvEND(mstr) = '\0';
  1534.     }
  1535.     else {
  1536.     I32 n;
  1537.  
  1538.     if ((n = SvCUR(mstr)) > msize)
  1539.         n = msize;
  1540.     Copy(mbuf, shm + mpos, n, char);
  1541.     if (n < msize)
  1542.         memzero(shm + mpos + n, msize - n);
  1543.     }
  1544.     return shmdt(shm);
  1545. #else
  1546.     fatal("shm I/O not implemented");
  1547. #endif
  1548. }
  1549.  
  1550. #endif /* SYSV IPC */
  1551.